<?php declare(strict_types=1);
/**
 * @author      xianganyall <xianganyall@gmail.com>
 * @copyright   2023-2025 owner
 **/

namespace Srv\Scripts\Tools;

use Srv\Libs\Boot;
use Srv\Libs\Common\CommFile;
use Srv\Libs\Common\CommJson;
use Srv\Libs\Common\CommTime;
use Srv\Libs\ConfModel\RouteConf;
use Srv\Libs\Frame\Conf;
use Srv\Libs\Frame\DTOAbstract;
use Srv\Libs\Frame\Route;
use Srv\Libs\Tools\ShellPrint;

require_once dirname(__DIR__, 2).'/Libs/Boot.php';
Boot::runConf('');

// 获取反射类参数Json内容
function getRefClassParamJsonString(string $className, array &$classNameExtList):string
{
    $classNameExtList   = [];
    $jsonStr            = '';
    $classNameObject    = new $className();
    if($classNameObject instanceof DTOAbstract){
        $dtoData        = $classNameObject->getDataJsonArray([], true);
        if(count($dtoData) > 0) $jsonStr = CommJson::encodeArrayPretty($dtoData);
    }
    if(strlen($jsonStr) < 1) return $jsonStr;
    return 'bodyData = '.$jsonStr.";\n";
}

// 生成唯一Id
function genPostmanUuId(string $string):string
{
    $stringMd5  = md5($string);
    return substr($stringMd5, 0, 8).'-'.substr($stringMd5, 8, 4).'-'.substr($stringMd5, 12, 4).'-'.substr($stringMd5, 16, 4).'-'.substr($stringMd5, 20, 12);
}
$initCode           = <<<INIT_CODE
let headSkipList = ['x-sig','x-key','x-sig-skip','x-dev-offset'];
let headKeyList = ['x-dev-id','x-dev-name','x-dev-system','x-dev-time','x-dev-version','x-dev-lang','x-dev-screen','x-dev-net','x-dev-location','x-dev-offset','x-app-key','x-app-platform','x-app-channel','x-app-nonce','x-app-token','x-sig','x-key','x-sig-skip'];
function delay(timeMill){ return new Promise(function(resolve,reject){ setTimeout(resolve, timeMill); }); };
function getEV(k){return pm.environment.get(k);}
function setEV(k,v){pm.environment.set(k,v);}
function getTime(){return ''+new Date().getTime();}
function getNonce(){return ''+parseInt(Math.random()*(Math.pow(10,16)-Math.pow(10,15))+Math.pow(10,15));}
function initApi(){
    setEV('x-dev-time', getTime());
    setEV('x-app-nonce', getNonce());
    setEV('x-dev-offset', '2880');
    setEV('x-key', 'NONCE');
    setEV('contentType', 'application/json');
    let bodyStr = typeof(bodyData)==='string'?bodyData:(Object.keys(bodyData).length>0?JSON.stringify(bodyData):'');
    setEV('BODY_STRING', bodyStr);
    let headStr = '';
    headKeyList.sort().forEach((v)=>{ if(!headSkipList.includes(v)) headStr += (headStr.length<1?'':'&')+v+'='+getEV(v); });
    setEV('x-sig', CryptoJS.SHA1(headStr+getEV('x-set-secret')+bodyStr).toString());
}
function requestApi(path, body){
    let bodyStr = typeof(body)==='string'?body:(Object.keys(body).length>0?JSON.stringify(body):'');
    let headStr = '';
    let headData = {};
    headKeyList.sort().forEach((v)=>{
        if(headSkipList.includes(v)) return;
        let _val = getEV(v);
        switch(v){
            case 'x-dev-time':{_val = getTime(); break;}
            case 'x-app-nonce':{_val = getNonce();break;}
        }
        headData[v] = _val;
        headStr += (headStr.length<1?'':'&')+v+'='+_val;
    });
    headData['x-sig']=CryptoJS.SHA1(headStr+getEV('x-set-secret')+bodyStr).toString();
    headData['x-dev-offset']= '2880';
    headData['Content-Type']= 'application/json';
    headData['x-key']= 'NONCE';
    return new Promise((resolve,reject)=>{
        pm.sendRequest(
            {'url':getEV('apiServerUrl')+path,'method':'POST','header':headData,body:{'mode':'raw','raw':bodyStr}},
            (err,response)=>{if(err){reject(err);}else{resolve(response.json());}}
        );
    });
}
INIT_CODE;
$autoSignCode       = <<<AUTO_CODE
pm.test("OK",function(){
    let jsonData = pm.response.json();
    pm.expect(jsonData.result).exist;
    if(jsonData.result.tokenData)pm.environment.set('x-app-token', jsonData.result.tokenData.tokenStr);
});
AUTO_CODE;

$platformList       = [
    'android'   => [
        'devName'       => 'PD1981;vivo;V1981A',
        'devSystem'     => 'Android 30',
        'appChannel'    => 'official',
        'bundleId'      => 'com.exp.app',
    ],
    'ios'       => [
        'devName'       => 'iPhone14,5',
        'devSystem'     => 'iOS 15.1.1',
        'appChannel'    => 'appstore',
        'bundleId'      => 'com.exp.app',
    ],
    'web_h5'    => [
        'devName'       => 'Chrome/96.0.4664.93',
        'devSystem'     => 'Linux x86_64',
        'appChannel'    => 'official',
        'bundleId'      => 'com.exp.web',
    ],
];
$apiServerUrl      = 'http://admdevxc.nilela.test/api';
$projectName        = Conf::getProjectConf()->getName();
$RouteConfList      = Conf::getRouteConfGroup()->getGroupNameList();
// 生成postman环境
foreach ($RouteConfList as $RouteConf){
    if(!($RouteConf instanceof RouteConf)) continue;
    $xSigSkipSecret     = $RouteConf->getSigSkipSecret();
    $xAppKey            = $RouteConf->getAppKey();
    $xAppSecret         = $RouteConf->getAppSecret();
    $groupName          = $RouteConf->getGroupName();
    foreach ($platformList as $platformName => $platformVal){
        $postManEnvName     = $projectName.'[Dev-'.$groupName.'-'.$platformName.']';
        $xDevName           = $platformVal['devName'];
        $xDevSystem         = $platformVal['devSystem'];
        $xAppChannel        = $platformVal['appChannel'];
        $xBundleId          = $platformVal['bundleId'];
        $postManEnvironment = [
            'id'            => genPostmanUuId($postManEnvName),
            'name'          => $postManEnvName,
            'values'        => [
                ['enabled' => true, 'key' => 'x-set-secret',    'value' => $xAppSecret],
                ['enabled' => true, 'key' => 'x-set-run',       'value' => ''],
                ['enabled' => true, 'key' => 'apiServerUrl',  'value' => $apiServerUrl],
                ['enabled' => true, 'key' => 'x-key',          'value' => 'NONCE'],
                ['enabled' => true, 'key' => 'x-dev-id',       'value' => 'AAAABBBB-CCCC-DDDD-EEEE-FF0123456001'],
                ['enabled' => true, 'key' => 'x-dev-name',     'value' => $xDevName],
                ['enabled' => true, 'key' => 'x-dev-system',   'value' => $xDevSystem],
                ['enabled' => true, 'key' => 'x-dev-version',  'value' => '1.0.0.1'],
                ['enabled' => true, 'key' => 'x-dev-lang',     'value' => 'en'],
                ['enabled' => true, 'key' => 'x-dev-screen',   'value' => '750x1334'],
                ['enabled' => true, 'key' => 'x-dev-net',      'value' => 'wifi'],
                ['enabled' => true, 'key' => 'x-dev-location', 'value' => '113.247983,23.173851'],
                ['enabled' => true, 'key' => 'x-dev-offset',   'value' => '28800'],
                ['enabled' => true, 'key' => 'x-app-key',      'value' => $xAppKey],
                ['enabled' => true, 'key' => 'x-app-platform', 'value' => $platformName],
                ['enabled' => true, 'key' => 'x-app-channel',  'value' => $xAppChannel.'/'.$xBundleId],
                ['enabled' => true, 'key' => 'x-dev-time',     'value' => ''],
                ['enabled' => true, 'key' => 'x-app-nonce',    'value' => ''],
                ['enabled' => true, 'key' => 'x-app-token',    'value' => ''],
                ['enabled' => true, 'key' => 'x-sig',          'value' => ''],
                ['enabled' => true, 'key' => 'x-sig-skip',     'value' => $xSigSkipSecret],
                ['enabled' => true, 'key' => 'contentType',    'value' => 'application/json'],
                ['enabled' => true, 'key' => 'BODY_STRING',    'value' => ''],
                ['enabled' => true, 'key' => 'initCode',       'value' => $initCode],
            ],
        ];
        $filePath           = Boot::getTmpPath().'postman.env.'.$groupName.'.'.$platformName.'.json';
        if(CommFile::writeFileString($filePath, CommJson::encodeArrayPretty($postManEnvironment), 'w')){
            ShellPrint::printSuccessString($filePath."\n");
        }else{
            ShellPrint::printErrorString($filePath."\n");
        }
    }
}
// 生成postman集合
$postManCollection  = [
    'info' => [
        '_postman_id'   => genPostmanUuId($projectName),
        'name'          => $projectName.'['.CommTime::getString('m-d H:i').']',
        'schema'        => 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json',
    ],
//    'item' => [],
];
$collectionEvent    = [
    [
        'listen'    => 'prerequest',
        'script'    => [
            'type'    => 'text/javascript',
            'exec'    => [
                'let bodyData={};let _url=\'\';',
                'eval(pm.environment.get("initCode"));(async()=>{initApi();})();',
            ],
        ],
    ],
    [
        'listen'    => 'test',
        'script'    => [
            'type'    => 'text/javascript',
            'exec'    => ['pm.test("Error Exists",function(){pm.expect(pm.response.json().result).exist;});'],
        ],
    ],
];
$collectionRequest      = [
    'method'        => 'POST',
    'header'        => [
        ['key' => 'x-dev-id',          'value' => '{{x-dev-id}}'],
        ['key' => 'x-dev-name',        'value' => '{{x-dev-name}}'],
        ['key' => 'x-dev-system',      'value' => '{{x-dev-system}}'],
        ['key' => 'x-dev-time',        'value' => '{{x-dev-time}}'],
        ['key' => 'x-dev-version',     'value' => '{{x-dev-version}}'],
        ['key' => 'x-dev-lang',        'value' => '{{x-dev-lang}}'],
        ['key' => 'x-dev-screen',      'value' => '{{x-dev-screen}}'],
        ['key' => 'x-dev-net',         'value' => '{{x-dev-net}}'],
        ['key' => 'x-dev-location',    'value' => '{{x-dev-location}}'],
        ['key' => 'x-dev-offset',      'value' => '{{x-dev-offset}}'],
        ['key' => 'x-app-key',         'value' => '{{x-app-key}}'],
        ['key' => 'x-app-platform',    'value' => '{{x-app-platform}}'],
        ['key' => 'x-app-channel',     'value' => '{{x-app-channel}}'],
        ['key' => 'x-app-nonce',       'value' => '{{x-app-nonce}}'],
        ['key' => 'x-app-token',       'value' => '{{x-app-token}}'],
        ['key' => 'x-sig',             'value' => '{{x-sig}}'],
        ['key' => 'x-key',             'value' => '{{x-key}}'],
        ['key' => 'x-sig-skip',        'value' => '{{x-sig-skip}}'],
        ['key' => 'Content-Type',      'value' => '{{contentType}}'],
    ],
    'body'          => [
        'mode'      => 'raw',
        'raw'       => '{{BODY_STRING}}',
        'options'   => ['raw' => ['language' => 'json']],
    ],
    'url'           => [
        'raw'       => '{{apiServerUrl}}',
        'host'      => ['{{apiServerUrl}}'],
        'path'      => [],
    ],
    'description'   => '',
];
$collectionResponse     = [];
$collectionTpl          = [
    'name'                      => '',
    'event'                     => $collectionEvent,
    'protocolProfileBehavior'   => ['disabledSystemHeaders' => ['content-type' => true]],
    'request'                   => $collectionRequest,
    'response'                  => $collectionResponse,
];
// 添加自动登录EMAIL
$collectionData                                     = $collectionTpl;
$requestPath                                        = explode('/', 'acc/signin/email');
$collectionData['name']                             = 'autoSignIn[Email]';
$collectionData['request']['description']           = '';
$collectionData['request']['url']['raw']            .= '/'.implode('/', $requestPath);
$collectionData['request']['url']['path']           = $requestPath;
$collectionData['event'][0]['script']['exec'][0]    = 'let bodyData={"email": "my.test-dev@exp.com", "verify":"123456"};';
$collectionData['event'][0]['script']['exec'][1]    = 'let _url="'.'/'.implode('/', $requestPath).'";';
$collectionData['event'][0]['script']['exec'][2]    = '';
$collectionData['event'][0]['script']['exec'][3]    = 'eval(pm.environment.get("initCode"));(async()=>{await requestApi("/acc/signin/email/code",{"email":bodyData.email});initApi();})();';
$collectionData['event'][1]['script']['exec'][0]    = $autoSignCode;
// 添加自动登录SMS
$collectionDataSms                                      = $collectionTpl;
$requestPath                                            = explode('/', 'acc/signin/mobile');
$collectionDataSms['name']                              = 'autoSignIn[Sms]';
$collectionDataSms['request']['description']            = '';
$collectionDataSms['request']['url']['raw']             .= '/'.implode('/', $requestPath);
$collectionDataSms['request']['url']['path']             = $requestPath;
$collectionDataSms['event'][0]['script']['exec'][0]     = 'let bodyData={"code": 86, "mobile": "18122787872", "verify":"123456"};';
$collectionDataSms['event'][0]['script']['exec'][1]     = 'let _url="'.'/'.implode('/', $requestPath).'";';
$collectionDataSms['event'][0]['script']['exec'][2]     = '';
$collectionDataSms['event'][0]['script']['exec'][3]     = 'eval(pm.environment.get("initCode"));(async()=>{await requestApi("/acc/signin/mobile/sms",{"code":bodyData.code,"mobile":bodyData.mobile});initApi();})();';
$collectionDataSms['event'][1]['script']['exec'][0]     = $autoSignCode;
// 添加自动登录-END
$defaultGroupName                                   = 'Index';
$postManCollectionList                              = [$defaultGroupName => ['name' => $defaultGroupName, 'item' => [$collectionData, $collectionDataSms]]];
// 生成API
$routeList                      = Route::initData();
foreach ($routeList as $routeGroupList){
    foreach ($routeGroupList as $groupName => $pathList){
        ksort($pathList);
        foreach ($pathList as $pathUrl => $pathData){
            $path               = ltrim($pathUrl, '/');
//            $class              = $pathData[0];
//            $method             = $pathData[1];
            $auth               = $pathData[2];
            $code               = $pathData[3];
            $DTO                = $pathData[4];
            $VO                 = $pathData[5];
            $Comment            = $pathData[6];
            $codeStr            = $code;
            $logText            = str_pad($groupName.':'.$path, 39, ' ', STR_PAD_RIGHT);
            $logText            .= str_pad($auth, 5, ' ', STR_PAD_RIGHT);
            $logText            .= str_pad($codeStr, 13, ' ', STR_PAD_RIGHT);
            $logText            .= str_pad($DTO, 76, ' ', STR_PAD_LEFT);
            $logText            .= str_pad($VO, 60, ' ', STR_PAD_LEFT);
            $logText            .= ' '.str_pad($Comment, 42, ' ', STR_PAD_RIGHT);
            $logText            .= "\n";
            $paramJsonStr       = '';
            if(strlen($DTO) > 0){
                $classNameRefList       = [];
                $classRefItemList       = [$DTO];
                while(count($classRefItemList) > 0){
                    $className          = array_shift($classRefItemList);
                    if(in_array($className, $classNameRefList, true)) continue;
                    $classNameRefList[] = $className;
                    $classNameExtList   = [];
                    $paramJsonStr       .= getRefClassParamJsonString($className, $classNameExtList);
                    if(count($classNameExtList) > 0) array_unshift($classRefItemList, ...$classNameExtList);
                }
            }
            $collectionData                                 = $collectionTpl;
            $requestPath                                    = explode('/', trim(ltrim(trim($path), '/')));
            $collectionData['name']                         = $Comment;
            $collectionData['request']['description']       = '';
            if(count($requestPath) > 0){
                $collectionData['request']['url']['raw']    .= '/'.implode('/', $requestPath);
                $collectionData['request']['url']['path']   = $requestPath;
            }
            $collectionData['event'][0]['script']['exec'][0]    = '';
            unset($collectionData['event'][0]['script']['exec'][0]);
            array_unshift($collectionData['event'][0]['script']['exec'], ...explode("\n", 'let bodyData={};'."\n".'let _url="'.'/'.implode('/', $requestPath).'";'."\n".$paramJsonStr));
            $pageTitle          = trim(ltrim(trim($path), '/'));
            $pageTitleSplit     = explode('/', $pageTitle);
            $catNameOne         = $pageTitleSplit[0]??'';
            $itemGroupName      = strlen($catNameOne) < 1 ? $defaultGroupName : ($groupName.':'.$catNameOne);
            if(!isset($postManCollectionList[$itemGroupName])){
                $postManCollectionList[$itemGroupName]              = ['name' => $itemGroupName, 'item' => [$collectionData]];
            }else{
                $postManCollectionList[$itemGroupName]['item'][]    = $collectionData;
            }
            ShellPrint::printString($logText, ShellPrint::COLOR_BLUE);
        }
    }
}
$postManCollection['item']  = array_values($postManCollectionList);
$filePath                   = Boot::getTmpPath().'postman.api.'.$projectName.'.json';
if(CommFile::writeFileString($filePath, CommJson::encodeArrayPretty($postManCollection), 'w')){
    ShellPrint::printSuccessString($filePath."\n");
}else{
    ShellPrint::printErrorString($filePath."\n");
}
echo "\n\n";
